/**
  ******************************************************************************
  * @file
  * @brief
  * @author samuel-zsy
  * @version V1.0.0
  * @date 2018/07/17
  ******************************************************************************
  */


/* Includes ------------------------------------------------------------------*/
#include "w5500.h"
#include "stm32f4xx.h"
#include "lwip_app.h"

extern uint8_t SocketBuff[];
DMA_InitTypeDef DMA_InitStructure;
uint8_t pTmpBuf1[SOCKET_BUFF_NUM + 3];
uint8_t pTmpBuf2[SOCKET_BUFF_NUM + 3];

/* Private defines -----------------------------------------------------------*/

/* Private Struct  -----------------------------------------------------------*/


/* Private enum    -----------------------------------------------------------*/


/* Private Variable  ---------------------------------------------------------*/
//Pointer

//Array
dev_w5500_t w5500 = //W5500
{
    .DRV = "SPI1",
    .PIN_CS = "D7",
    .PIN_MOSI = "B5",
    .PIN_MISO = "B4",
    .PIN_SCK = "B3",
    .PIN_INT = "D5",
    .PIN_RESET = "D6",
    .SPI_SPEED = SPI_SPEED_HIGH,
    .SPI_CS_MODE = SPI_CS_NULL,
};
//Const

/* Private function prototypes -----------------------------------------------*/
/**
  * @brief  配置指定SPI1的GPIO引脚
  * @retval None
* 输入参数：无
* 输出参数：GPIO_TypeDef* GPIOB - PB3,PB4,PB5配置为SPI1 SCK,MISO,MOSI
*           GPIO_TypeDef* GPIOD - PD6,PD7配置为GPIO口输出模式，PD6-RESET，PD7-CS(低电平有效)
* 返回值：无
  */
static void SPI_GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;

	//打开时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // DMA2 的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOD,ENABLE);

	//打开端口复用
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);
	//PB3->SCK	 					 
	GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_3;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_NOPULL;  	
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	//PB4->MISO
	GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_4;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	//PB5->MOSI	
	GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_5;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	//PD7->CS,初始化片选输出引脚
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_Init(GPIOD, &GPIO_InitStruct);
	//PD6->RESET,初始化复位引脚
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_Init(GPIOD, &GPIO_InitStruct);
	//拉高片选
	GPIO_SetBits(GPIOD,GPIO_Pin_7);
	
}

void DMA_Configuration(void)
{
	DMA_DeInit(DMA2_Stream0);	//SPI1_TX_DMA_STREAM
	DMA_DeInit(DMA2_Stream3);	//SPI1_RX_DMA_STREAM
}

/**
  * @brief  配置W5500 SPI接口相关参数
  * @retval None
* 输入参数：无
* 输出参数：SPI_TypeDef* SPI1 - SPI1端口参数
* 返回值：无
  */
void SPI_Configuration(void)
{
	SPI_InitTypeDef SPI_InitStruct;

	SPI_GPIO_Configuration();

	SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
	SPI_InitStruct.SPI_Direction= SPI_Direction_2Lines_FullDuplex;
	SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
	SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;//SPI_CPOL_High;
	SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;//SPI_CPHA_2Edge;        //W5500支持SPI模式0及模式3
	SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStruct.SPI_CRCPolynomial = 7;
	SPI_Init(SPI1,&SPI_InitStruct);
	
#if !defined (SPI_DMA)	
	SPI_Cmd(SPI1, ENABLE);
#endif
	
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) ;
}

/**
  * @brief  写1字节数据到SPI总线
  * @param  TxData 写到总线的数据
  * @retval None
  */
void SPI_WriteByte(uint8_t TxData)
{	
	while((SPI1->SR&SPI_I2S_FLAG_TXE)==(uint16_t)RESET);	 //等待发送区空		  
	SPI1->DR = TxData;	 	  						         //发送一个byte 
	while((SPI1->SR&SPI_I2S_FLAG_RXNE)==(uint16_t)RESET);    //等待接收完一个byte  
	SPI1->DR;	
}
/**
  * @brief  从SPI总线读取1字节数据
  * @retval 读到的数据
  */
uint8_t SPI_ReadByte(void)
{	
	while((SPI1->SR&SPI_I2S_FLAG_TXE)==(uint16_t)RESET);	//等待发送区空			  
	SPI1->DR = 0xFF;	 	  								//发送一个空数据产生输入数据的时钟 
	while((SPI1->SR&SPI_I2S_FLAG_RXNE)==(uint16_t)RESET);   //等待接收完一个byte  
	
	return SPI1->DR;	
}

void SPI_WriteWord(uint16_t TxData)
{	
	while((SPI1->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);  // 等待发送区空		  
	SPI1->DR = TxData;	 	  						         // 发送一个 16 位数据 
	while((SPI1->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET); // 等待接收完一个 16 位数据
	(void)SPI1->DR;                                           // 读取 DR 以清除 RXNE 标志
}

uint16_t SPI_ReadWord(void)
{	
	while((SPI1->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);  // 等待发送区空			  
	SPI1->DR = 0xFFFF;                                        // 发送一个空数据产生输入数据的时钟 (16 位) 
	while((SPI1->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET); // 等待接收完一个 16 位数据  
	
	return (uint16_t)SPI1->DR;	                               // 返回接收到的 16 位数据
}
/***********************************************************************************
 * @brief w5500 SPI片选
 * ex:
 * @par
 * None
 * @par Called functions:
 * None
 * @retval void None
 **********************************************************************************/
void W5500_CSCmd(int State)
{
	switch (State)
    {
		case CS_ENABLE:
			GPIO_SetBits(GPIOD,GPIO_Pin_7);
			break;
		case CS_DISENABLE:
			GPIO_ResetBits(GPIOD,GPIO_Pin_7);
			break;
		default:
			break;
    }
}


void SPI_DMA_WRITE(uint8_t* Addref, uint8_t* pTxBuf, uint16_t tx_len)
{
	uint16_t i;

	memset(pTmpBuf1, 0, tx_len + 3);

	pTmpBuf1[0] = Addref[0];
	pTmpBuf1[1] = Addref[1];
	pTmpBuf1[2] = Addref[2];

	for(i=0; i<tx_len; i++)
		pTmpBuf1[3 + i] = pTxBuf[i];

    DMA_InitStructure.DMA_BufferSize = (uint16_t)(tx_len + 3);
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(SPI1->DR));
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize =  DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

	/* Configure Tx DMA */
	DMA_InitStructure.DMA_Channel = DMA_Channel_3;
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) pTmpBuf1;
	DMA_Init(DMA2_Stream3, &DMA_InitStructure);

    /* Configure Rx DMA */
	DMA_InitStructure.DMA_Channel = DMA_Channel_3;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) pTmpBuf1;
	DMA_Init(DMA2_Stream0, &DMA_InitStructure);

	/* Enable the DMA channel */
	W5500_CSCmd(0);

	/* Enable the DMA SPI TX Stream */
	DMA_Cmd(DMA2_Stream3, ENABLE);
	/* Enable the DMA SPI RX Stream */
	DMA_Cmd(DMA2_Stream0, ENABLE);

	/* Enable the SPI Rx DMA request */
	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

    SPI_Cmd(SPI1, ENABLE);
	 
    /* Waiting the end of Data transfer */
    while (DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_TCIF3)==RESET);
    while (DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0)==RESET);



	W5500_CSCmd(1);

	DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_TCIF3);
	DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0);

	DMA_Cmd(DMA2_Stream3, DISABLE);
	DMA_Cmd(DMA2_Stream0, DISABLE);

	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, DISABLE);
	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, DISABLE);
	
	SPI_Cmd(SPI1, DISABLE);
}


void SPI_DMA_READ(uint8_t* Addref, uint8_t* pRxBuf, uint16_t rx_len)
{
	uint16_t i;

	memset(pTmpBuf1, 0, rx_len + 3);
	memset(pTmpBuf2, 0, rx_len + 3);

	pTmpBuf1[0] = Addref[0];
	pTmpBuf1[1] = Addref[1];
	pTmpBuf1[2] = Addref[2];
    
    for(int i = 0;i < rx_len;i++)
    {
        pTmpBuf1[3 + i] = 0xff;
    }

#if 0
	printf("rx len: %d\r\n", rx_len);
	printf("Rx Data: ");
	for(i=0; i<rx_len; i++)
		printf("%02X ", pRxBuf[i]);
	printf("\r\n");

	printf("pTmpBuf1: ");
	for(i=0; i<rx_len + 3; i++)
		printf("%02X ", pTmpBuf1[i]);
	printf("\r\n");
	

#endif

    DMA_InitStructure.DMA_BufferSize = (uint16_t)(rx_len + 3);
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable ;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(SPI1->DR));
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize =  DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

	/* Configure Tx DMA */
	DMA_InitStructure.DMA_Channel = DMA_Channel_3;
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) pTmpBuf1;
	DMA_Init(DMA2_Stream3, &DMA_InitStructure);

    /* Configure Rx DMA */
	DMA_InitStructure.DMA_Channel = DMA_Channel_3;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) pTmpBuf2;
	DMA_Init(DMA2_Stream0, &DMA_InitStructure);


	/* Enable the DMA channel */

	/* Enable the SPI Rx DMA request */
	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

	W5500_CSCmd(0);

	/* Enable the DMA SPI TX Stream */
	DMA_Cmd(DMA2_Stream3, ENABLE);
	/* Enable the DMA SPI RX Stream */
	DMA_Cmd(DMA2_Stream0, ENABLE);


    SPI_Cmd(SPI1, ENABLE);
    /* Waiting the end of Data transfer */
    while (DMA_GetFlagStatus(DMA2_Stream3, DMA_FLAG_TCIF3)==RESET);
    while (DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0)==RESET);

//	printf("DMA_READ after select\r\n");
//	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
//	{}


//	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET)
//	{}

	W5500_CSCmd(1);

//	printf("DMA_READ after deselect\r\n");
//	while((DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET)){}

//	printf("2\r\n");
	DMA_ClearFlag(DMA2_Stream3, DMA_FLAG_TCIF3);
	DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0);

	DMA_Cmd(DMA2_Stream3, DISABLE);
	DMA_Cmd(DMA2_Stream0, DISABLE);

	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, DISABLE);
	SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, DISABLE);

	SPI_Cmd(SPI1, DISABLE);
//	for(i=0; i<rx_len; i++)
//		pRxBuf[i] = pTmpBuf2[3 + i];

	memcpy(pRxBuf, pTmpBuf2 + 3, rx_len);

#if 0
	printf("Rx Data: ");
	for(i=0; i<rx_len; i++)
		printf("%02X ", pRxBuf[i]);
	printf("\r\n");
#endif
}

/***********************************************************************************
 * @brief 复位W5500
 * ex:
 * @par
 * None
 * @par Called functions:
 * None
 * @retval void None
* 输入参数：无
* 输出参数：无
* 返回值：无
 **********************************************************************************/
void W5500_Reset(void)
{
	GPIO_ResetBits(GPIOD,GPIO_Pin_6);  //该引脚需要保持低电平至少500 us，才能重置 W5500
	SoftDelay_ms(2);
	GPIO_SetBits(GPIOD,GPIO_Pin_6);
	SoftDelay_ms(100);
}

/***********************************************************************************
* @brief  初始化W5500 SPI接口参数配置，复位W5500
 * ex:
 * @par
 * None
 * @par Called functions:
 * None
 * @retval
* 输入参数：无
* 输出参数：无
* 返回值：无
 **********************************************************************************/
void W5500_Init(void)
{
	//W5500 SPI接口初始化
	SPI_Configuration();
	
    //DMA复位
    DMA_Configuration();
    
	//复位W5500
	W5500_Reset();
}

#if 0
/***********************************************************************************
 * @brief
 * ex:
 * @par
 * None
 * @par Called functions:
 * None
 * @retval
 **********************************************************************************/
int W5500_Init(dev_w5500_t* this)
{
	//spi config
	this->private.drv_spix.DRV    	   			= this->DRV;
	this->private.drv_spix.PIN_CS      			= this->PIN_CS;
	this->private.drv_spix.PIN_MISO    			= this->PIN_MISO;
    this->private.drv_spix.PIN_MOSI    			= this->PIN_MOSI;
    this->private.drv_spix.PIN_SCK     			= this->PIN_SCK;											
	this->private.drv_spix.CS_EN       			= this->SPI_CS_MODE;
	this->private.drv_spix.SPEED	   			= this->SPI_SPEED;	
	this->private.drv_spix.ORDER       			= SPI_MSB;
	this->private.drv_spix.CPOL        			= SPI_CPOL_H;
	this->private.drv_spix.CPHA        			= SPI_CPHA_2;
	this->private.drv_spix.TRANS       			= SPI_TRANS_BYTE;
	this->private.drv_spix.CS_DELAY_US 			= 10;
	
	if(Drv_Spi_Init(&this->private.drv_spix) < 0){
        return -1;
    }
	
	//soft cs io config
	this->private.drv_gpio_spics.PIN 			= this->PIN_CS;
	this->private.drv_gpio_spics.MODE			= OUTPUT_UP;
	this->private.drv_gpio_spics.INIT_LEVEL 	= HIGHT_LEVEL;
	
	if(Drv_Gpio_Init(&this->private.drv_gpio_spics) < 0){
		return -1;
	}
	
	//int io config
	if (this->PIN_INT != NULL)
	{
		this->private.drv_gpio_int.PIN 			= this->PIN_INT;
		this->private.drv_gpio_int.MODE			= INPUT_DOWN;
		this->private.drv_gpio_int.INIT_LEVEL 	= HIGHT_LEVEL;
		
		if(Drv_Gpio_Init(&this->private.drv_gpio_int) < 0){
			return -1;
		}		
	}

	//reset io config
	if (this->PIN_RESET != NULL)
	{
		this->private.drv_gpio_reset.PIN 			= this->PIN_RESET;
		this->private.drv_gpio_reset.MODE			= OUTPUT_UP;
		this->private.drv_gpio_reset.INIT_LEVEL 	= HIGHT_LEVEL;
		
		if(Drv_Gpio_Init(&this->private.drv_gpio_reset) < 0){
			return -1;
		}		
	}
	
	this->Reset			  						= W5500_Reset;
	this->CSCmd									= W5500_CSCmd;
	
	w5500.Reset();
}
#endif



/******************* (C) COPYRIGHT 2018 CIQTEK Samuel *****END OF FILE****/
